Hammerspoon CLI script

  • 2025-04-18

A Hammerspoon script that, when you select text and input a shell command, executes the command by piping the selected text into standard input and copies the standard output to the clipboard.

For example, if you select a specific column in Google Sheets and enter grep "X" | sort | uniq, the result of filtering cells containing X, then sorting, and removing duplicates will be copied to the clipboard.

Code

local os = require("os")

local obj = {}

function obj:init()
    self.statusIcon = hs.menubar.new()
    return self
end

function obj:setStatus(emoji)
    self.statusIcon:setTitle(emoji)
end

function obj:clearStatus()
    self.statusIcon:setTitle("")
end

function obj:bindHotkeys(mapping)
    local spec = { run = hs.fnutils.partial(self.run, self) }
    hs.spoons.bindHotkeysToSpec(spec, mapping)
    return self
end

function obj:run()
    -- Copy the text to the clipboard
    hs.eventtap.keyStroke({ "cmd" }, "c")
    hs.timer.usleep(0.001)

    -- Get the text from the clipboard
    local input = hs.pasteboard.getContents()
    if input == nil then
        hs.alert("Please select the text first")
        return
    end

    -- Get the command
    local cmd = self:getCommand()
    if cmd == nil then
        return
    end

    -- Run the command
    self:setStatus("")
    hs.task.new(os.getenv("SHELL"), function(code, out, err)
        if code ~= 0 then
            hs.dialog.blockAlert("Error", err, "Ok")
        else
            hs.alert("Updated clipboard")
        end
        self:clearStatus()
    end, {
        "-i", "-c", "pbpaste | " .. cmd .. " | pbcopy"
    }):start()
end

function obj:getCommand()
    local focusedApp = hs.window.frontmostWindow():application()

    local button, userInput = hs.dialog.textPrompt("Enter the command", "", "llm \"Summerize\"", "Ok", "Cancel")

    if focusedApp then
        hs.timer.doAfter(0.01, function()
          focusedApp:activate()
        end)
    end

    if button == "Ok" then
        return userInput
    else
        return nil
    end
end

return obj

2025 © ak